/** @file absfs.h
	@brief Abstract filesystem */

#ifndef G3_ABSFS_H
#define G3_ABSFS_H

#include "log.h"
#include "text.h"
#include "singleton.h"

#include "f_filehandler.h"

#include <map>
#include <set>
#include <string>

/** Directory delimiters */
#define ABSFS_DIR_DELIMS	":\t \\/"

namespace G3 {

/** @class ABS_FILE_ENTRY
	@brief Filesystem file entry
	\note Confirm the comments - I have forgotten how this code works*/
class ABS_FILE_ENTRY {
	public:
		/**
			@brief Constructor that sets the directory path and file path
			@param[in] Path1 The directory path
			@param[in] Path2 The file path
		*/
		ABS_FILE_ENTRY (const std::string &Path1, const std::string &Path2);

        /** The directory path */
		std::string DirPath;
		/** The file path */
		std::string FilePath;

        /**
			@brief Operator for file entry assignment
			@param[in] f Reference to the file entry to be copied
			@return Reference to the freshly assigned entry
		*/
		ABS_FILE_ENTRY& operator=(const ABS_FILE_ENTRY &f);

        /**
			@brief Simply concatenates the DirPath and FilePath members
			@return The full path to the file
		*/
		std::string GetWholePath ();
};

/** @class ABS_REAL_STRUCT
	@brief A link object that points to a real path. These link objects are used for fast sorting.
	\todo Confirm the comments - I have forgotten how this code works*/
class ABS_REAL_STRUCT {
	public:
		/**
			@brief Constructor that just NULLs the pointers
		*/
		ABS_REAL_STRUCT ();

        /** Iterator of the corresponding real path in the set */
		std::set<std::string>::iterator Iter;
		/** Pointer to the real path string */
		std::string *Pointer;
        /** Pointer to the parent local path class */
		struct ABS_LOCAL_PATH *Parent;

		/**
			@brief Assignment operator
			@param[in] rs Reference to the other real struct to be copied
			@return Reference to the freshly assigned struct
		*/
		ABS_REAL_STRUCT& operator=(const ABS_REAL_STRUCT &rs);
};

/** @class ABS_LOCAL_PATH
	@brief Local (abstract) path that corresponds to multiple real paths
	\todo Confirm the comments - I have forgotten how this code works*/
class ABS_LOCAL_PATH {
	public:
		/**
			@brief Constructor that sets the local path and log pointer
		*/
		ABS_LOCAL_PATH (const char *Local = NULL, LOG *pLog = &MainLog);

        /** Pointer to a log */
		LOG *Log;

        /** The local path */
		std::string LocalPath;
		/** Real paths that correspond to this local path */
		std::set<std::string> RealPaths;

		/**
			@brief Assignment operator for copying this class
			@param[in] lp Reference to the local path class to be copied
			@return Reference to the fresh copy
		*/
		ABS_LOCAL_PATH& operator=(const ABS_LOCAL_PATH &lp);
		/**
			@brief Needed for alphabetic sorting
			@param[in] lp Reference to the local path class for this class to be compared against
			@return True if this is < than lp
		*/
		bool operator<(const ABS_LOCAL_PATH &lp) const;
		/**
			@brief Needed for alphabetic comparison
			@param[in] lp Reference to the local path class for this class to be compared against
			@return True if this is == to lp
		*/
		bool operator==(const ABS_LOCAL_PATH &lp) const;

		/**
			@brief Finds a real path from the set
			@param[in] RealPath The path to be searched from the set
			@return A real path class. If the path was not found, then the 'Pointer' member of the
			real path class is NULL.
		*/
		ABS_REAL_STRUCT FindReal (const char *RealPath);

		/**
			@brief Inserts a real path into the set
			@param[in] RealPath The path to be inserted
			@return A real path class. If the path could not be added, then the 'Pointer' member of the
			real path class is NULL.
		*/
		ABS_REAL_STRUCT AddReal (const char *RealPath);
};

/** @class ABS_LOCAL_STRUCT
	@brief A link object that points to a local path. These link objects are used for fast sorting.
	\todo Confirm the comments - I have forgotten how this code works*/
class ABS_LOCAL_STRUCT {
	public:
		/**
			@brief Constructor that NULLs the pointer
		*/
		ABS_LOCAL_STRUCT ();

        /** Iterator to the corresponding local path class in the set */
		std::set<ABS_LOCAL_PATH>::iterator Iter;
		/** Pointer to the local path class */
		ABS_LOCAL_PATH *Pointer;

		/**
			@brief Assignment operator for copying
			@param[in] lc Reference to the local struct to be copied
			@return Reference to the freshly copied local struct
		*/
		ABS_LOCAL_STRUCT& operator=(const ABS_LOCAL_STRUCT &lc);
};

/** @class ABSFS
	@brief Abstract filesystem
	\todo Confirm the comments - I have forgotten how this code works*/
class ABSFS: public SINGLETON <ABSFS> {
	public:
		/**
			@brief Constructor that NULLs the pointer
		*/
		ABSFS ();

        /** Pointer to a log */
		G3::LOG *Log;

		/**
			@brief Finds a local path from the set
			@param[in] Local The local path to be searched for
			@return Local struct that points to the local path.
			The 'Pointer' member of the struct is NULL when the local path
			was not found.
		*/
		ABS_LOCAL_STRUCT FindLocal (const char *Local);

		/**
			@brief Adds a local path into the set
			@param[in] Local The local path to be added
			@return Local struct that points to the local path.
			The 'Pointer' member of the struct is NULL when the local path
			couldn't be added.
		*/
		ABS_LOCAL_STRUCT AddLocal (const char *Local);

		/**
			@brief Mounts a real path as a local (abstract) path
			@param[in] Path The real path
			@param[in] Local The local (abstract) path
			@return True on success, false on failure. Fails if
			the real directory doesn't exist.
		*/
		bool MountDir (const char *Path, const char *Local);

		/**
			@brief Unmounts a real path
			@param[in] Path The real path
			@return True on success, false on failure. Fails if
			the path isn't mounted.
		*/
		bool UnMountDir (const char *Path);

		/**
			@brief Unmounts all real paths
		*/
		void UnMountAll ();

		/**
			@brief Gets the real path that corresponds to the given local path
			@param[in] LocalFile The local file path
			@return The real path. Returns an empty string if the local path
			doesn't exist (nothing is mounted in it).
		*/
		std::string GetPath (const char *LocalFile);

        /**
            @brief Checks if a file with an abstract path exists
            @param[in] LocalFile The abstract file path
            @return True if it does and false if it does not
        */
		bool FileExists (const std::string &LocalFile);

		/**
			@brief Dumps the filesystem into the log
		*/
		void Dump ();

	private:
        /** Set of local paths */
		std::set<ABS_LOCAL_PATH> LocalPaths;
		/** Set of their backward links */
		std::map<std::string, ABS_REAL_STRUCT> BackwardLinks;
        /** A cache of file path queries for fast access */
		std::map<std::string, ABS_FILE_ENTRY> CachedFilePaths;
};

/** The main abstract filesystem singleton */
extern ABSFS MainFilesys;

}

#endif
